/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2012/07/12
* File: OGLGraphicsBuffer.cpp
* Blog: http://www.cnblogs.com/zengqh/
**/

#include "../GraphicsBuffer.h"
#include "OGLGraphicsBuffer.h"

OGLGraphicsBuffer::OGLGraphicsBuffer(BufferUsage usage, 
									 u32 access_hint, 
									 GLenum target, 
									 void* init_data, 
									 u32 size)
									 : GraphicsBuffer(usage, access_hint)
									 , _target(target)
									  
{
	rf_assert(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);

	_size_in_byte = size;

	glGenBuffers(1, &_vb);
	if (init_data)
	{
		glBindBuffer(target, _vb);

		glBufferData(_target, _size_in_byte, init_data, (usage == BU_Static) ? GL_STATIC_DRAW : GL_DYNAMIC_DRAW);
	}
}

OGLGraphicsBuffer::~OGLGraphicsBuffer()
{
	if (_vb != 0) glDeleteBuffers(1, &_vb);
}

void OGLGraphicsBuffer::resize(u32 size_in_byte)
{
	_size_in_byte = size_in_byte;

	glBindBuffer(_target, _vb);

	glBufferData(_target, _size_in_byte, NULL, (_buffer_usage == BU_Static) ? GL_STATIC_DRAW : GL_DYNAMIC_DRAW);
}

void* OGLGraphicsBuffer::_map(BufferAccess ba)
{
	GLenum flag;
	switch(ba)
	{
	case BA_Read_Only:
		flag = GL_READ_ONLY;
		break;

	case BA_Write_Only:
		flag = GL_WRITE_ONLY;
		break;

	case BA_Read_Write:
		flag = GL_READ_WRITE;
		break;
	}

	void* p = NULL;
	
	glBindBuffer(_target, _vb);
	p = glMapBuffer(_target, flag);

	return p;
}

void OGLGraphicsBuffer::_unmap()
{
	glBindBuffer(_target, _vb);
	glUnmapBuffer(_target);
}

void OGLGraphicsBuffer::active()
{
	glBindBuffer(_target, _vb);
}

void OGLGraphicsBuffer::copyToBuffer(const GraphicsBuffer& other)
{
	/* we can make it more effective in >= ogl 3.1 
	 * or the GL_ARB_copy_buffer is enabled.
	 * glCopyBufferSubData function.
	 * we make it simple here.
	 */
	GraphicsBuffer::Mapper lhs_mapper(*this, BA_Read_Only);
	GraphicsBuffer::Mapper rhs_mapper(*this, BA_Read_Only);

	std::copy(lhs_mapper.Pointer<u8*>(), lhs_mapper.Pointer<u8*>() + _size_in_byte,
		rhs_mapper.Pointer<u8*>());
}